const shell = require('shelljs')
const path = require('path')
const inquirer = require("inquirer")

const { sleep, get } = require('./common')
const { logs, WECHAT_CLI_PATH, getPlatformInfo, openReady, compiled } = require('./platform-common')


function isStringError (msg) {
    return msg && /error/.test(msg) && /message/.test(msg)
}

function isNeedLogin (err) {
    return err && /登录/.test(err) && !/开发者/.test(err)
}

function retryLogin () {
    return new Promise((resolve, reject) => {
        let retryCount = 0
        logs.error('登录失效', '请扫描二维码登录开发者工具')
        logs.wait('二维码准备中 ...')
        const r = () => {
            shell.exec(`${WECHAT_CLI_PATH} login -f terminal --qr-size small`, async (code, stdout) => {
                if (!isStringError(stdout)) {
                    resolve()
                } else {
                    if (retryCount < 3) {
                        retryCount++
                        logs.error(`登录失败，进行第${retryCount}次重试...`)
                        await sleep(2000)
                        r()
                    } else {
                        reject(stdout)
                    }
                }
            })
        }
        r()
    })
}

function hasLogin (platformInfo) {
    return new Promise((resolve, reject) => {
        shell.cd(platformInfo.ideDir)
        const hasIsLogin = () => {
            shell.exec(`${WECHAT_CLI_PATH} islogin`, (code, stdout) => {
                if (code === 0) {
                    let data = JSON.parse(stdout)
                    if (data.login) {
                        resolve()
                    } else {
                        retryLogin()
                            .then(() => {
                                hasIsLogin()
                            })
                            .catch(() => {
                                reject(new Error(stdout))
                            })
                    }
                } else {
                    logs.error(code, stdout)
                    reject(new Error(stdout))
                }
            })
        }
        hasIsLogin()
    })
}

async function openIde (config, env, platform, basePath, isBuildBefore = false) {
    const platformInfo = getPlatformInfo(platform, config, basePath, env)

    function openProject () {
        function exec (resolve) {
            // 打开小程序项目
            shell.exec(`${WECHAT_CLI_PATH} open --project ${platformInfo.projectDir} --color=always`, (code, stdout) => {
                if (isNeedLogin(stdout)) {
                    retryLogin()
                        .finally(() => {
                            exec(resolve)
                        })
                } else {
                    resolve(code, stdout)
                }
            })
        }

        return new Promise(async (resolve) => {
            logs.line()
            logs.wait('正在打开小程序开发工具 ...')
            logs.log('打开小程序项目 -> ' + platformInfo.projectDir.cyan)
            await sleep(3000)
            exec(resolve)
        })
    }

    async function open (resolve) {
        shell.cd(platformInfo.ideDir)
        await openProject()
        resolve()
    }

    return new Promise(resolve => {
        openReady ({
            ideDir: platformInfo.ideDir,
            projectDir: platformInfo.projectDir,
            flagFile: 'project.config.json',
            remove: isBuildBefore
        })
            .then(res => {
                if (res === true) {
                    compiled({ config, NODE_ENV: env, UNI_PLATFORM: platform, PRESET_PATH: basePath })
                    hasLogin(platformInfo)
                        .then(() => {
                            open(resolve)
                        })
                        .catch(() => {
                            resolve()
                        })
                } else {
                    resolve()
                }
            })
    })
}

async function upload(config, env, type, basePath) {
    // 微信项目源码路径
    const weixinDevtoolsPath = get(config, 'mp-weixin.ideDir')
    const EXEC_CODE_TYPE = env === 'development' ? 'dev' : 'build'
    const WEIXIN_PRESET_PATH = path.resolve(basePath, `./dist/${EXEC_CODE_TYPE}/${type}`)
    const VERSION = get(config, 'mp-weixin.version')
    const DESCRIPTION = get(config, 'mp-weixin.description', '') + '，cli-upload，env=' + global.NODE_ENV
    const APPID = get(config, 'configData.platform.wx.appId')

    async function _upload (resolve) {
        // 打开小程序项目
        const uploadShell = `${WECHAT_CLI_PATH} upload --project ${WEIXIN_PRESET_PATH} -v ${VERSION} -d '${DESCRIPTION}' --color=always`
        const clearShell = `
            ${WECHAT_CLI_PATH} cache --clean compile --project ${WEIXIN_PRESET_PATH} --color=always
            ${WECHAT_CLI_PATH} cache --clean file --project ${WEIXIN_PRESET_PATH} --color=always
            `

        shell.cd(weixinDevtoolsPath)

        logs.log('清除编译缓存')
        shell.exec(clearShell, async (code, stdout) => {
            if (isStringError(stdout)) {
                if (isNeedLogin(stdout)) {
                    logs.error('清除编译缓存失败，需要登录')
                    retryLogin()
                        .then(() => {
                            _upload(resolve)
                        })
                        .catch(() => {
                            resolve(code, stdout)
                        })
                    return
                } else {
                    logs.log('清除编译缓存失败，仍继续上传')
                }
            } else {
                logs.success('清除编译缓存成功')
            }

            logs.log('上传项目', WEIXIN_PRESET_PATH.cyan)
            logs.log('AppId', APPID)
            logs.log('Version', VERSION)
            logs.log('Description', DESCRIPTION)
            logs.wait('开始上传...')
            logs.line()

            await sleep(3000)
            // 上传
            shell.exec(uploadShell, async (code, stdout) => {
                if (resolve) {
                    resolve(code, stdout)
                }

                if (isStringError(stdout)) {
                    await sleep(100)
                    const choices = [
                        { name: '关闭开发工具 - 重新上传代码', value: 'closeRetry' },
                        { name: '重新上传代码', value: 'retry' },
                        { name: '退出', value: 'exit' }
                    ]
                    inquirer
                        .prompt({
                            type: 'list',
                            name: 'action',
                            message: `上传代码失败，是否重新尝试？`,
                            choices: choices
                        })
                        .then(answer => {
                            const action = answer.action
                            if (action === 'closeRetry') {
                                if (shell.exec(`${WECHAT_CLI_PATH} quit`).code !== 0) {
                                    logs.error('退出编译工具失败')
                                    shell.exit(1)
                                } else {
                                    logs.success('退出编译工具成功')
                                }
                            }
                            if (action !== 'exit') {
                                upload(config, env, type, basePath)
                            }
                        })
                }
            })
        })
    }

    return new Promise(resolve => {
        if (VERSION) {
            _upload(resolve)
        } else {
            logs.error('未设置版本号，上传取消')
        }
    })
}

module.exports = {
    openIde,
    upload
}
